/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.bingoogolapple.bgabanner;

import cn.bingoogolapple.bgabanner.transformer.PageTransformer;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.PageSlider;
import ohos.app.Context;

import java.util.HashMap;
import java.util.Map;

public class PageSliders extends PageSlider
        implements PageSlider.PageChangedListener {
    private static final int SLID_LEFT = 0;
    private static final int SLID_LEFT_ELASTIC = 1;
    private static final int SLID_RIGHT = 2;
    private static final int SLID_RIGHT_ELASTIC = 3;
    private static final int SLID_NONE = 4;
    private Map<Integer, Component> mViewCache = new HashMap<>();
    private PageTransformer mPageTransformer;
    private PageChangedListener mPageChangedListener;
    private int mLastScrollState;

    /**
     * Viewpager 滑动进度
     */
    private float itemPosOffset = 0;

    /**
     * Viewpager 滑动像素
     */
    private int itemPosOffsetPixels = 0;

    /**
     * Viewpager 当前定位
     */
    private int currentItemPos;

    /**
     * 构造
     *
     * @param context 上下文
     */
    public PageSliders(Context context) {
        super(context);
        init();
    }

    /**
     * 构造
     *
     * @param context 上下文
     * @param attrSet 属性
     */
    public PageSliders(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init();
    }

    /**
     * 构造
     *
     * @param context 上下文
     * @param attrSet 属性
     * @param styleName styleName
     */
    public PageSliders(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
    }

    /**
     * setViewCache
     *
     * @param mViewCache
     */
    public void setViewCache(Map<Integer, Component> mViewCache) {
        this.mViewCache = mViewCache;
    }

    private void init() {
        addPageChangedListener(this);
    }

    /**
     * onPageSliding
     *
     * @param itemPos 位置
     * @param itemPosOffset 偏移
     * @param itemPosOffsetPixels 像素
     */
    @Override
    public void onPageSliding(int itemPos, float itemPosOffset, int itemPosOffsetPixels) {
        this.currentItemPos = itemPos;
        this.itemPosOffset = itemPosOffset;
        if (this.itemPosOffset > 1) {
            this.itemPosOffset = this.itemPosOffset - 1;
        }
        this.itemPosOffsetPixels = itemPosOffsetPixels;
        if (mPageChangedListener != null) {
            mPageChangedListener.onPageSliding(itemPos, itemPosOffset, itemPosOffsetPixels);
        }
        if (mPageTransformer != null) {
            int realSlidState = getRealSlidState();
            if (realSlidState != SLID_NONE) {
                mLastScrollState = realSlidState;
            }
            switch (mLastScrollState) {
                case SLID_LEFT:
                    scrollLeft(itemPos, this.itemPosOffset);
                    break;
                case SLID_RIGHT:
                    scrollRight(itemPos, this.itemPosOffset);
                    break;
                case SLID_LEFT_ELASTIC:
                    // 向左滑动但未达到临界回弹
                    elasticLeft(itemPos, this.itemPosOffset);
                    break;
                case SLID_RIGHT_ELASTIC:
                    // 向右滑动但未达到临界回弹
                    elasticRight(itemPos, this.itemPosOffset);
                    break;
                default:
                    break;
            }
        }
    }

    private void scrollLeft(int position, float positionOffset) {
        Component in = mViewCache.get(position + 1);
        Component out = mViewCache.get(position);
        mPageTransformer.transformPage(in, 1 - positionOffset);
        mPageTransformer.transformPage(out, 0 - positionOffset);
    }

    private void elasticLeft(int position, float positionOffset) {
        Component in = mViewCache.get(position);
        Component out = mViewCache.get(position + 1);
        mPageTransformer.transformPage(out, positionOffset);
        mPageTransformer.transformPage(in, -1 + positionOffset);
    }

    private void scrollRight(int position, float positionOffset) {
        // 从左往右滑动
        Component in = mViewCache.get(position - 1);
        Component out = mViewCache.get(position);
        mPageTransformer.transformPage(out, positionOffset);
        mPageTransformer.transformPage(in, -1 + positionOffset);
    }

    private void elasticRight(int position, float positionOffset) {
        Component out = mViewCache.get(position - 1);
        Component in = mViewCache.get(position);
        mPageTransformer.transformPage(in, 1 - positionOffset);
        mPageTransformer.transformPage(out, 0 - positionOffset);
    }

    @Override
    public void onPageSlideStateChanged(int state) {
        if (mPageChangedListener != null) {
            mPageChangedListener.onPageSlideStateChanged(state);
        }
    }

    @Override
    public void onPageChosen(int itemPos) {
        if (mPageChangedListener != null) {
            mPageChangedListener.onPageChosen(itemPos);
        }
    }

    /**
     * 设置动画
     *
     * @param pageTransformer 动画
     */
    public void setPageTransformer(PageTransformer pageTransformer) {
        this.mPageTransformer = pageTransformer;
    }

    /**
     * 设置Page切换监听器
     *
     * @param pageChangedListener 监听器
     */
    public void setPageChangedListener(PageChangedListener pageChangedListener) {
        this.mPageChangedListener = pageChangedListener;
    }

    /**
     * 获取真实滑动状态
     *
     * @return RealSlidState
     */
    protected int getRealSlidState() {
        if (itemPosOffset == 1) {
            return SLID_NONE;
        }

        if (getCurrentSlidingState() == ohos.agp.components.PageSlider.SLIDING_STATE_DRAGGING) {
            if (itemPosOffsetPixels > 0) {
                return SLID_LEFT;
            } else if (itemPosOffsetPixels < 0) {
                return SLID_RIGHT;
            }
        } else if (getCurrentSlidingState() == ohos.agp.components.PageSlider.SLIDING_STATE_SETTLING) {
            if (currentItemPos != getCurrentPage()) {
                if (itemPosOffsetPixels > 0) {
                    return SLID_RIGHT;
                } else if (itemPosOffsetPixels < 0) {
                    return SLID_LEFT;
                }
            } else {
                if (itemPosOffsetPixels > 0) {
                    return SLID_LEFT_ELASTIC;
                } else if (itemPosOffsetPixels < 0) {
                    return SLID_RIGHT_ELASTIC;
                }
            }
        }
        return SLID_NONE;
    }
}
